﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Packaging;
using System.Xml.Linq;

namespace Exentials.Xoox.Spreadsheet
{
    public class XWorksheet : XDocumentBase<WorksheetPart>
    {
        //4 <element name="sheetPr" type="CT_SheetPr" minOccurs="0" maxOccurs="1"/>
        //5 <element name="dimension" type="CT_SheetDimension" minOccurs="0" maxOccurs="1"/>
        //6 <element name="sheetViews" type="CT_SheetViews" minOccurs="0" maxOccurs="1"/>
        //7 <element name="sheetFormatPr" type="CT_SheetFormatPr" minOccurs="0" maxOccurs="1"/>
        //8 <element name="cols" type="CT_Cols" minOccurs="0" maxOccurs="unbounded"/>
        //9 <element name="sheetData" type="CT_SheetData" minOccurs="1" maxOccurs="1"/>
        //10 <element name="sheetCalcPr" type="CT_SheetCalcPr" minOccurs="0" maxOccurs="1"/>
        //11 <element name="sheetProtection" type="CT_SheetProtection" minOccurs="0" maxOccurs="1"/>
        //12 <element name="protectedRanges" type="CT_ProtectedRanges" minOccurs="0" maxOccurs="1"/>
        //13 <element name="scenarios" type="CT_Scenarios" minOccurs="0" maxOccurs="1"/>
        //14 <element name="autoFilter" type="CT_AutoFilter" minOccurs="0" maxOccurs="1"/>
        //15 <element name="sortState" type="CT_SortState" minOccurs="0" maxOccurs="1"/>
        //16 <element name="dataConsolidate" type="CT_DataConsolidate" minOccurs="0" maxOccurs="1"/>
        //17 <element name="customSheetViews" type="CT_CustomSheetViews" minOccurs="0" maxOccurs="1"/>
        //18 <element name="mergeCells" type="CT_MergeCells" minOccurs="0" maxOccurs="1"/>
        //19 <element name="phoneticPr" type="CT_PhoneticPr" minOccurs="0" maxOccurs="1"/>
        //20 <element name="conditionalFormatting" type="CT_ConditionalFormatting" minOccurs="0" maxOccurs="unbounded"/>
        //22 <element name="dataValidations" type="CT_DataValidations" minOccurs="0" maxOccurs="1"/>
        //23 <element name="hyperlinks" type="CT_Hyperlinks" minOccurs="0" maxOccurs="1"/>
        //24 <element name="printOptions" type="CT_PrintOptions" minOccurs="0" maxOccurs="1"/>
        //25 <element name="pageMargins" type="CT_PageMargins" minOccurs="0" maxOccurs="1"/>
        //26 <element name="pageSetup" type="CT_PageSetup" minOccurs="0" maxOccurs="1"/>
        //27 <element name="headerFooter" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/>
        //28 <element name="rowBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/>
        //29 <element name="colBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/>
        //30 <element name="customProperties" type="CT_CustomProperties" minOccurs="0" maxOccurs="1"/>
        //31 <element name="cellWatches" type="CT_CellWatches" minOccurs="0" maxOccurs="1"/>
        //32 <element name="ignoredErrors" type="CT_IgnoredErrors" minOccurs="0" maxOccurs="1"/>
        //33 <element name="smartTags" type="CT_SmartTags" minOccurs="0" maxOccurs="1"/>
        //34 <element name="drawing" type="CT_Drawing" minOccurs="0" maxOccurs="1"/>
        //35 <element name="legacyDrawing" type="CT_LegacyDrawing" minOccurs="0" maxOccurs="1"/>
        //36 <element name="legacyDrawingHF" type="CT_LegacyDrawing" minOccurs="0" maxOccurs="1"/>
        //37 <element name="picture" type="CT_SheetBackgroundPicture" minOccurs="0" maxOccurs="1"/>
        //38 <element name="oleObjects" type="CT_OleObjects" minOccurs="0" maxOccurs="1"/>
        //39 <element name="controls" type="CT_Controls" minOccurs="0" maxOccurs="1"/>
        //40 <element name="webPublishItems" type="CT_WebPublishItems" minOccurs="0" maxOccurs="1"/>
        //41 <element name="tableParts" type="CT_TableParts" minOccurs="0" maxOccurs="1"/>
        //42 <element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>

        private XElementSequenceContainer<XElementBase> _worksheet;
        private XPageMargins _pageMargins;
        private XWorkbook _parent;

        private XColumnInformation _cols;
        private XElementList<XMergeCell> _mergeCells;
        private XSheetData _rows;

        public XWorksheet(WorksheetPart part)
            : base(part)
        {
            _worksheet = new XElementSequenceContainer<XElementBase>("worksheet");
            _worksheet.GetXElement().Add(new XAttribute(XNamespace.Xmlns + "r", SpreadsheetSchemas.Relationships.NamespaceName));
            Document.Add(_worksheet.GetXElement());
            _worksheet.Add(_rows = new XSheetData());
        }

        public XWorkbook Workbook
        {
            get { return _parent; }
            set { _parent = value; }
        }

        public IEnumerable<XCell> this[Reference reference]
        {
            get
            {
                for (int row = reference.Row; row <= reference.RowBound; row++)
                {
                    XRow xrow = _rows[row];
                    if (xrow == null) _rows.Add(xrow = new XRow() { Index = row });
                    for (int col = reference.Column; col <= reference.ColumnBound; col++)
                    {
                        XCell cell = xrow[col];
                        if (cell == null) xrow.Add(cell = new XCell() { Reference = new Reference(row, col), Worksheet = this });
                    }
                }
                IEnumerable<XCell> cells = _rows.Where(t => t.Index >= reference.Row && t.Index <= reference.RowBound).SelectMany(t => t).Where(t => t.Reference.Column >= reference.Column && t.Reference.Column <= reference.ColumnBound);
                return cells;
            }
        }

        public XCell this[int row, int column]
        {
            get
            {
                return this[new Reference(row, column)].First();
            }
        }

        internal XElementList<XMergeCell> MergeCells
        {
            get
            {
                if (_mergeCells == null)
                {
                    _mergeCells = new XMergeCells();
                    _worksheet.Add(_mergeCells);
                }
                return _mergeCells;
            }
        }

        public void Merge(Reference range)
        {
            MergeCells.Add(new XMergeCell() { Reference = range });
        }

        public XColumnInformation ColumnInformation
        {
            get
            {
                if (_cols == null) _worksheet.Add(_cols = new XColumnInformation());
                return _cols;
            }
        }

        public XPageMargins PageMargins
        {
            get
            {
                if (_pageMargins == null) _worksheet.Add(_pageMargins = new XPageMargins());
                _worksheet.GetXElement().Descendants();
                DocumentFormat.OpenXml.Spreadsheet.PageMargins pm = new DocumentFormat.OpenXml.Spreadsheet.PageMargins();
                return _pageMargins;
            }
        }

        public void SetColumnInformation(int minColumn, int maxColumn)
        {
            ColumnInformation.Add(new XCol(minColumn, maxColumn) { Collapsed = true });
        }

        public void SetAutoFilter(Reference range)
        {
            XElement element = Document.Root.Element(SpreadsheetSchemas.MainSchema + "autoFilter");
            if (element != null) element.Remove();
        }
    }
}
